/**
 * 
 */
package biz.innovasoft.nodb.impl;

import java.io.Serializable;
import java.util.Collection;
import java.util.Map;

import org.prevayler.foundation.DeepCopier;

import biz.innovasoft.nodb.Repository;
import biz.innovasoft.nodb.RepositoryException;
import biz.innovasoft.nodb.StoreValidator;
import biz.innovasoft.nodb.ValidationException;
import biz.innovasoft.nodb.util.IndexUtils;

/**
 * 
 * @author Diego Miranda
 *
 */
public class StoreHelper implements Serializable {

	private static final long serialVersionUID = 1636317280646847592L;

	private GenericRepository repository;
	
	public StoreHelper (GenericRepository repository) {
		this.repository = repository;
	}
	
	@SuppressWarnings("unchecked")
	public Object store(Object object) throws RepositoryException {
		if (object instanceof Collection) {
			return this.store((Collection<?>)object, Repository.INDEX_YES);
		}
		return this.store(object, Repository.INDEX_YES);
	}

	public Long store(Object object, int index)
			throws RepositoryException {
				
		if (!(object instanceof Serializable)) {
			throw new RepositoryException ("Object must be serializable.");
		}
		
		if (IndexUtils.isPrimitiveClass(object.getClass())) {
			throw new RepositoryException ("Can't store an instance of: " + object.getClass().getCanonicalName());
		}
		validate (object);
		
		Long oid = repository.objectId;
		boolean fromStack = false;
		synchronized (repository.availableOids) {
			if (repository.availableOids.size() > 0) {
				oid = repository.availableOids.pop();
				fromStack = true;
			}
		}
		
		repository.getObjects().put(oid, object);
		repository.addStoredClass(object.getClass());
		repository.getIndexHelper().indexObject(oid, object, index);
		
		if (!fromStack) {
			repository.objectId++;
		} else {
			repository.availableOids.push(oid);
		}
		
		return oid;
		
	}

	public Long[] store(Collection<?> objects, int index)
			throws RepositoryException {
		int idx = 0;
		Long []ids = new Long[objects.size()];
		for (Object object : objects) {
			ids[idx++] = store(DeepCopier.deepCopy(object), index);
		}
		return ids;
	}
	
	private void validate (Object object) {
		Map<String,StoreValidator> validators = repository.getStoreValidator(object.getClass());
		if ( validators == null ) {
			return;
		}
		for (String key : validators.keySet()) {
			StoreValidator validator = validators.get(key);
			if (!validator.canStore(object)) {
				throw new ValidationException ("Object cant be stored. Validator: " + key + " has failed.", 0l, key);
			}
		}
	}
}
